Mybatis入门和简单Demo
一、Mybatis的诞生
回顾下传统的数据库开发,JDBC和Hibernate是使用最普遍的技术,但这两种ORM框架都存在一定的局限性:
JDBC:最原生的技术,简单易学,执行速度快,效率高,适合大数据量的操作,但存在代码繁琐,需要关心驱动的加载,连接的关闭等操作,对于分页等复杂用法,需要自己手动写代码实现。
Hibernate:以面向对象的方式设计和访问,不用写SQL,不用管底层具体数据库的语法,但对于多表操作灵活性差,复杂的HQL难写难理解,执行速度慢,只适合小数据量的操作。
基于上述技术的瓶颈,诞生了一种在这两者之间找到平衡点的ORM框架,结合它们的优点,摒弃它们的缺点,这就是myBatis,现今myBatis被广泛的企业所采用。MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)
二、Mybatis入门Demo(基于MySQL)
Mybatis程序的运行流程大概如下:
(1)通过Reader对象读取src目录下的mybatis.xml配置文件(该文件名称可自定义,主要用来配置数据源,类型别名以及mapper文件的总配置文件)
(2)通过SqlSessionFactoryBuilder对象创建SqlSessionFactory对象
(3)从当前线程,即ThreadLocal中获取SqlSession对象
(4)开启事务(默认开启)
(5)通过SqlSession对象读取对应Mapper.xml映射文件中的操作编号,从而读取sql语句
(6)提交或回滚事务
(7)关闭SqlSession对象,并且分开当前线程与SqlSession对象,让GC尽早回收
基于上述步骤开始Mybatis入门Demo案例的编写:
步骤1.引入Mybatis所需jar包依赖
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
步骤2.准备数据源db.properties并配置mybatis.xml文件
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/aa
mysql.username=root
mysql.password=123456
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 加载类路径下的属性文件 --> <properties resource="db.properties"> </properties> <!-- 设置实体类的类型别名 --> <typeAliases> <typeAlias type="com.jyk.mybatis.Student" alias="student"/> </typeAliases> <!-- 设置一个默认的连接环境信息,支持多数据源 --> <environments default="mysql_env"> <!-- 连接环境信息,取一个唯一的编号 --> <environment id="mysql_env"> <!-- mybatis使用的jdbc事务管理方式 --> <transactionManager type="jdbc"> </transactionManager> <!-- mybatis使用连接池方式来获取链接 --> <dataSource type="pooled"> <!-- 配置与数据库交互的四个属性 --> <property name="driver" value="${mysql.driver}"/> <property name="url" value="${mysql.url}"/> <property name="username" value="${mysql.username}"/> <property name="password" value="${mysql.password}"/> </dataSource> </environment> </environments>
<mappers> <mapper resource="com/jyk/mybatis/StudentMapper.xml"/> </mappers> </configuration>
步骤3.编写需要操作的实体类com.jyk.mybatis.Student记录学生信息
package com.jyk.mybatis; public class Student { private String id; private String name; private String age; private String sex; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Student(String id, String name, String age, String sex) { super(); this.id = id; this.name = name; this.age = age; this.sex = sex; } public Student() { super(); } }
步骤4.配置StudentMapper.xml,配置namespace,需要唯一,一般以需要操作的实体类全路径为准,也可为其他值。然后是配置实体类与实际表的映射关系resultMap,type属性:实体全路径名,可在mybatis.xml文件中统一配置,如在上述mybatis.xml中已配置<typeAlias type="com.jyk.mybatis.Student" alias="student"/>,则此处实体类全路径可用student代替
注:当实体属性名与表字段名不一样时,此处信息必配,若一致,则此处配置可选。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- 名称空间namespace必须唯一 --> <mapper namespace="studentNamespace"> <!-- resultMap标签:映射实体与表,非主键属性标签 type属性:实体全路径名,可在mybatis.xml文件中统一配置 id属性:为实体与表的映射取一个唯一的编号 --> <resultMap type="student" id="studentMap"> <!-- id标签:映射主键属性 result标签:映射非主键属性 property属性:实体属性名 column属性:表的字段名 --> <id property="id" column="id"/> <result property="name" column="name"/> <result property="age" column="age"/> <result property="sex" column="sex"/> </resultMap> </mapper>
步骤5.编写Mybatis通用工具类,通过Reader对象读取src目录下的mybatis.xml配置文件,并测试连接
package com.jyk.mybatis.util; import java.io.IOException; import java.io.Reader; import java.sql.Connection; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; /* * MyBatis工具类 */ public class MyBatisUtil { private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>(); private static SqlSessionFactory sqlSessionFactory; //静态块加载src目录下的mybatis配置文件 static{ try { Reader reader = Resources.getResourceAsReader("mybatis.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } catch (IOException e) { e.printStackTrace(); } } /* * 禁止外界通过new方法创建 */ private MyBatisUtil(){} /* * 获取sqlsession */ public static SqlSession getSqlSession() { //从当前线程中获取sqlSession对象 SqlSession sqlSession = threadLocal.get(); //判断SqlSession对象是否为空 if(sqlSession==null) { //在SqlSessionFactory对象非空的情况下,获取SqlSession对象 sqlSession = sqlSessionFactory.openSession(); //将SqlSession对象与当前线程绑定在一起 threadLocal.set(sqlSession); } return sqlSession; } /* * 关闭sqlsession与当前线程分开 */ public static void closeSqlSession() { //从当前线程中获取SqlSession对象 SqlSession sqlSession = threadLocal.get(); if(sqlSession != null) { //关闭SqlSession对象 sqlSession.close(); //分开当前线程与SqlSession对象的关系,目的是尽早进行垃圾回收 threadLocal.remove(); } } /* * 测试方法 */ public static void main(String[] args) { Connection conn = MyBatisUtil.getSqlSession().getConnection(); if(conn==null) { System.out.println("连接为空"); } else { System.out.println("连接不为空"); } } }
步骤6.编写CRUD语句,在mapper文件中编写,此处编写在上述已经配置好实体类映射的StudentMapper.xml文件中
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- 名称空间namespace必须唯一 --> <mapper namespace="studentNamespace"> <!-- resultMap标签:映射实体与表 type属性:实体全路径名 id属性:为实体与表的映射取一个唯一的编号 --> <resultMap type="student" id="studentMap"> <!-- id标签:映射主键属性 result标签:映射非主键属性 property属性:实体属性名 column属性:表的字段名 --> <id property="id" column="id"/> <result property="name" column="name"/> <result property="age" column="age"/> <result property="sex" column="sex"/> </resultMap> <!-- insert标签:sql插入语句 id属性:该sql语句的唯一标签 parameterType:要执行的dao中的方法的参数,如果是类的话,必须使用全路径名 #{xx}:mybatis特有语法,用来替代jdbc中的?占位符 --> <insert id="add1"> insert into student(id,name,age,sex) values("1","admin","22","男") </insert> <insert id="add2" parameterType="student"> insert into student(id,name,age,sex) values(#{id},#{name},#{age},#{sex}) </insert> <!-- <insert id="add3" parameterType="student"> insert into student(id,name,age,sex) values(#{id},#{name},#{age},#{sex}) </insert> --> </mapper>
步骤7.编写DAO,利用上述配置完成的文件和写好的通用工具类MyBatisUtil对学生信息进行增删该查
package com.jyk.mybatis; import org.apache.ibatis.session.SqlSession; import com.jyk.mybatis.util.MyBatisUtil; public class StudentDao { /* * 增加的方法1 */ public void add1() { SqlSession sqlSession = null; try{ sqlSession = MyBatisUtil.getSqlSession(); //事务开始(默认) //读取StudentMapper.xml配置文件中的sql语句,对应的sql语句由{名称空间.sql的id指定} int i = sqlSession.insert("studentNamespace.add1"); System.out.println("本次操作影响了"+i+"行数据"); //事务提交 sqlSession.commit(); }catch(Exception e){ e.printStackTrace(); //事务回滚 sqlSession.rollback(); throw e; }finally{ MyBatisUtil.closeSqlSession(); } } /* * 增加的方法2 */ public void add2(Student stu) { SqlSession sqlSession = null; try{ sqlSession = MyBatisUtil.getSqlSession(); //事务开始(默认) //读取StudentMapper.xml配置文件中的sql语句 int i = sqlSession.insert("studentNamespace.add2",stu); System.out.println("本次操作影响了"+i+"行数据"); //事务提交 sqlSession.commit(); }catch(Exception e){ e.printStackTrace(); //事务回滚 sqlSession.rollback(); throw e; }finally{ MyBatisUtil.closeSqlSession(); } } /* * 增加的方法3 * 往数据库添加记录必须要添加事务,没有事务添加不进去 */ public void add3(Student stu) { SqlSession sqlSession = null; try{ sqlSession = MyBatisUtil.getSqlSession(); //事务开始(默认) //读取StudentMapper.xml配置文件中的sql语句 int i = sqlSession.insert("studentNamespace.add3",stu); System.out.println("本次操作影响了"+i+"行数据"); sqlSession.commit(); }catch(Exception e){ e.printStackTrace(); //事务回滚 sqlSession.rollback(); throw e; }finally{ MyBatisUtil.closeSqlSession(); } } public static void main(String[] args) { StudentDao sd = new StudentDao(); sd.add1(); sd.add2(new Student("64","kaiye","23","男")); } }